﻿Function Save-Folder
{ 
    [cmdletbinding(SupportsShouldProcess=$True)]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $source,
        
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [ValidateScript({Test-Path $_ -PathType Container})] 
        [String] 
        $destination,
        
        [Parameter(Mandatory=$false)] 
        [switch]
        $keepPreviousBackup,

        [Parameter(Mandatory=$false)] 
        [Int32]
        $NumberOfkeepPreviousBackup = 2
         
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start Save-Folder from $source to $destination"
        if ($keepPreviousBackup)
        {
            Write-Verbose "Keep previous version enable and keep $NumberOfKeepPreviousBackup previous version"
        }
    }
    End
    {
        write-verbose "End Save-Folder from $source to $destination"
        $watch.Stop();
        Write-Verbose "Function duration : $($watch.Elapsed)"
    }
    Process 
    { 
        Try 
        {
            if ((Test-Path $source) -ne $true)
            {
                Write-Warning "$source doesn't exist, stop save-folder"
                return
            }

            #Get Source folder
            $itemSource = Get-Item -Path $source
            if ($itemSource.gettype().Name -ne "DirectoryInfo")
            {
                throw New-Object System.Exception -ArgumentList "This cmdlet can only backup folders"
            }
            
            
            Write-Verbose "Found $($itemSource.Name) in $($itemSource.Parent.FullName)"

            #Check Target Folder : We start from its parent
            $destinationFolder = [System.IO.Path]::Combine($destination, $itemSource.Parent)
            $existDestination = [System.IO.Path]::Combine($destinationFolder, $itemSource.Name)
            if (Test-Path $existDestination)
            {
                if ($keepPreviousBackup)
                {
                    Write-Verbose "Found previous backup and keep them"
                }
                else
                {
                    Write-Verbose "Found previous backup $($itemSource.Name) and delete them from $destinationFolder"
                    Delete-Folders -source $destinationFolder -pattern $itemSource.Name
                    
                }
            }

            #Create the destination Folder before if it doesn't exist                
            if ((Test-Path $destinationFolder) -eq $false)
            {
    			Write-verbose "Create destination folder $destinationFolder before copy"
                New-Item -Path $destinationFolder -ItemType Container
            }
            
            #Backup the folder
			Write-verbose "Copy folders $source to $destinationFolder"
            Copy-Item -Path $source -Destination $destinationFolder -Recurse

            #TODO : get-backupitem to check that backup is ok ??
            #$itemDestination = Get-Item -Path $existDestination

        } 
        Catch 
        { 
            write-warning "Error accessing : $($_.Exception.Message)"   
        } 
    } 
}

Function Delete-Folders
{ 
    [cmdletbinding(SupportsShouldProcess=$True)]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [ValidateScript({Test-Path $_ -PathType Container})] 
        [String] 
        $source,
        
        [Parameter(Mandatory=$true)] 
        [String] 
        $pattern = "*"
                 
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start Delete-Folders $pattern from $source"
    }
    End
    {
        write-verbose "End Delete-Folders $pattern from $source"
        $watch.Stop();
        Write-Verbose "Function duration : $($watch.Elapsed)"
    }
    Process 
    { 
        Try 
        {

            #Get Source folder
            $itemSource = Get-Item -Path $source
            Write-Verbose "Found $($itemSource.Name) in $($itemSource.Parent.FullName)"

            if (($itemSource.Name -eq $itemSource.Root.Name) -and ($pattern -eq "*"))
            {
                throw New-Object System.NotSupportedException
            }

            #Get folders according the pattern
            $lstFolders = Get-ChildItem -Path $source -Filter $pattern -Force
            Write-Verbose "Delete $($lstFolders.Length) folders in $source"

            if ($lstFolders -eq $null) {return}
                        
            if (($lstFolders.GetType().Name -eq "DirectoryInfo") -or ($lstFolders.Length -gt 0))
            {
                $lstFolders | ForEach-Object -Process {
                    Write-Verbose "deleting $($_.Name)"
                    Remove-Item $_.FullName -Recurse -Force -ErrorAction Stop            
                    Write-Verbose "End deleting $($_.Name)"

                }
            }
                

        } 
        Catch 
        { 
            write-Error "Error Delete-Folder : $($_.Exception.Message)"   
        } 
    } 
}


Function Export-ZipContent
{ 
    [cmdletbinding(SupportsShouldProcess=$True, ConfirmImpact="Low")]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [ValidateScript({Test-Path $_ -PathType Leaf})] 
        [String] 
        $zipFile,
        
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [ValidateScript({Test-Path $_ -PathType Container})] 
        [String] 
        $destination,
        
        [switch]
        $cleanBefore,

        [switch]
        $Force
         
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start Export-ZipContent $zipFile to $destination"
    }
    End
    {
        write-verbose "End Export-ZipContent $zipFile to $destination"
        $watch.Stop();
        Write-Verbose "Function duration : $($watch.Elapsed)"
    }
    Process 
    { 
        Try 
        { 
            $shellApplication = new-object -com shell.application
		    $zipPackage = $shellApplication.NameSpace($zipFile)
            
            $file = Get-Item $zipFile
            
            $target = [System.IO.Path]::combine($destination, $file.BaseName)
            
            #test if target folder exists and delete it or throw exception
            if (Test-Path -Path $target)
            {
                Write-Verbose "Destination $target already exists" 
                if ($cleanBefore -eq $true)
                {
                    Delete-Folders -source $destination -pattern $file.BaseName
                }
                else
                {
                    throw New-Object System.IO.IOException
                }
            }
            
            #Create folder cible
            if($PSCmdlet.ShouldProcess("Exported zip file '$($zipfile)' to '$($destination)'",
                            "Export zip file '$($zipfile)' to '$($destination)' ?",
                            "Exporting zip file '$($zipfile)' to '$($destination)'" )) 
            {
                
                if ($Force -or $PSCmdlet.ShouldContinue("Are you sure wou want to export the zip file '$($zipfile)' to '$($destination)'","Export-ZipContent"))
                {
                    $container = New-Item -Path $target -ItemType Container
                    Write-Verbose "$target has been created"
		    

                    #retrieve destination folder and unzip
                    $destinationFolder = $shellApplication.NameSpace($target)            
		            $destinationFolder.CopyHere($zipPackage.Items())

                    #retieve the target to validate its creation
                    $targetItem = Get-Item $target            
                }
            }

            

        } 
        Catch 
        { 
            Write-Error "Error $($_.Exception.Message)"   
        } 
    } 
}


Function Get-BinariesVersion
{
     Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [ValidateScript({Test-Path $_ -PathType Container})] 
        [String] 
        $Path
        )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start Get-BinariesVersion in  $Path"
    }
    End
    {
        write-verbose "End Get-BinariesVersion in  $Path"
        $watch.Stop();
        Write-Verbose "Get-BinariesVersion : $($watch.Elapsed)"
    }
    Process
    {
        
        Get-ChildItem -Path $Path -Recurse | Where-Object {($_.Extension -eq '.dll') -or ($_.Extension -eq '.exe')} | ForEach-Object {

            $file = Get-ItemProperty $_.FullName
            Write-Output $file.VersionInfo
        }
    }
}


Function Copy-PackageContent
{
    [cmdletbinding(SupportsShouldProcess=$True)]
     Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [ValidateScript({Test-Path $_ -PathType Container})] 
        [String] 
        $Path,
        
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $PackageName,
        
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $Destination
        )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start Copy-FolderContent from $Path to $Destination"
    }
    End
    {
        write-verbose "End Copy-FolderContent from $Path to $Destination"
        $watch.Stop();
        Write-Verbose "Copy-FolderContent : $($watch.Elapsed)"
    }
    Process
    {
               
        #Test Destination and ensure folder
        if ((Test-Path $Destination -PathType Container) -eq $false)
        {
            Write-Verbose "Destination $Destination doesn't exist, create it"
            New-Item $Destination -ItemType Container | Out-Null
        }

        
        #Find package in Path directory
        $package = Get-ChildItem -Path $Path -Recurse -Filter $PackageName

                
        Get-ChildItem -Path $package.FullName | ForEach-Object {

            Copy-Item -Path $_.FullName -Destination $Destination -Recurse -Force
        }
    }
}

Function Copy-PackageContent_v2
{
        [cmdletbinding(SupportsShouldProcess=$True)]
        Param(
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [ValidateScript({Test-Path $_ -PathType Container})] 
        [String] 
        $Path,
        
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $PackageName,
        
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $Destination
        )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start Copy-FolderContent from $Path to $Destination"
    }
    End
    {
        write-verbose "End Copy-FolderContent from $Path to $Destination"
        $watch.Stop();
        Write-Verbose "Copy-FolderContent : $($watch.Elapsed)"
    }
    Process
    {
               
        #Find package in Path directory
        $package = Get-ChildItem -Path $Path -Recurse -Filter $PackageName

        #Test Destination and ensure folder
        if ((Test-Path $Destination -PathType Container) -eq $false)
        {
            Write-Verbose "Destination $Destination doesn't exist, create it"
            New-Item $Destination -ItemType Container | Out-Null
        }
        
        #Check that destination is not the root drive
        $itemDestination = Get-Item -Path $Destination
        if ($itemDestination.Name -eq $itemDestination.Root.Name)
        {
            throw New-Object System.NotSupportedException -ArgumentList "Can't copy Content on the root drive"
        }
               
        #Call msdeploy to synchronize package with destination
        $commandToExecute = '& "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" -verb:sync -source:contentPath={0} -dest:contentPath={1}'
        $commandToExecute = [System.String]::Format($commandToExecute, $($package.FullName), $Destination)
        
        
         #Add whatif support
        if($PSBoundParameters['Whatif'])
        {
            $commandToExecute += " -Whatif"
        }
        
        Write-verbose "Command to execute : $commandToExecute"
        Invoke-Command -ScriptBlock ([scriptblock]::create($commandToExecute))
                
    }
}

Function Save-Folder_V2
{ 
    [cmdletbinding(SupportsShouldProcess=$True)]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $source,
        
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $destination,
        
        [Parameter(Mandatory=$false)] 
        [switch]
        $keepPreviousBackup,

        [Parameter(Mandatory=$false)] 
        [Int32]
        $NumberOfkeepPreviousBackup = 2
         
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start Save-Folder from $source to $destination"
        if ($keepPreviousBackup)
        {
            Write-Verbose "Keep previous version enable and keep $NumberOfKeepPreviousBackup previous version"
        }
    }
    End
    {
        write-verbose "End Save-Folder from $source to $destination"
        $watch.Stop();
        Write-Verbose "Function duration : $($watch.Elapsed)"
    }
    Process 
    { 
        if ((Test-Path $source) -ne $true)
        {
            Write-Warning "$source doesn't exist, stop save-folder_v2"
            return
        }
    
        #Get Source folder
        $itemSource = Get-Item -Path $source
        if ($itemSource.gettype().Name -ne "DirectoryInfo")
        {
            throw New-Object System.Exception -ArgumentList "This cmdlet can only backup folders"
        }
        
        
        Write-Verbose "Found $($itemSource.Name) in $($itemSource.Parent.FullName)"

        #Check Target Folder : We start from its parent
        $destinationFolder = [System.IO.Path]::Combine($destination, $itemSource.Parent)
        $existDestination = [System.IO.Path]::Combine($destinationFolder, $itemSource.Name)
        if (Test-Path $existDestination)
        {
            if ($keepPreviousBackup)
            {
                Write-Verbose "Found previous backup and keep them"
            }
            else
            {
                Write-Verbose "Found previous backup $($itemSource.Name) and delete them from $destinationFolder"
                Delete-Folders -source $destinationFolder -pattern $itemSource.Name                    
            }
        }

        #Create the destination Folder before if it doesn't exist                
        if ((Test-Path $existDestination) -eq $false)
        {
			Write-verbose "Create destination folder $destinationFolder before copy"
            New-Item -Path $existDestination -ItemType Container | Out-Null
        }
        
        #Backup the folder
			Write-verbose "Copy folders $source to $destinationFolder"
        
        #Calculate destination path archive file name
        $archiveFileName = $itemSource.Name + "_" + $(Get-Date -Format "yyyyMMdd_hhmmss") + ".zip"
        $archiveFilePath = Join-Path -Path $existDestination -ChildPath $archiveFileName
        
        #Call msdeploy to synchronize package with destination
        $commandToExecute = '& "C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" -verb:sync -source:contentPath={0} -dest:package={1}'
        $commandToExecute = [System.String]::Format($commandToExecute, $source, $archiveFilePath)
    
    
         #Add whatif support
        if($PSBoundParameters['Whatif'])
        {
            $commandToExecute += " -Whatif"
        }
        
        Write-verbose "Command to execute : $commandToExecute"
        Invoke-Command -ScriptBlock ([scriptblock]::create($commandToExecute))
            
        
        #Copy-Item -Path $source -Destination $destinationFolder -Recurse

        #TODO : get-backupitem to check that backup is ok ??
        #$itemDestination = Get-Item -Path $existDestination

    } 
}
